package org.ainlolcat.ainscience.entity;

import org.ainlolcat.ainscience.Controller;
import org.ainlolcat.ainscience.UpdateListener;
import org.ainlolcat.ainscience.column.Column;
import org.ainlolcat.ainscience.column.ColumnImpl;
import org.ainlolcat.ainscience.column.threshold.LessThanThreshold;
import org.ainlolcat.ainscience.column.threshold.MoreThanThreshold;
import org.ainlolcat.ainscience.column.threshold.Threshold;
import org.ainlolcat.ainscience.column.threshold.ThresholdHelper;
import org.ainlolcat.ainscience.matrix.MatrixFileParser;
import org.ainlolcat.ainscience.project.Project;
import org.ainlolcat.ainscience.statistics.StatisticsCollectorImpl;
import org.ainlolcat.ainscience.templates.Template;
import org.ainlolcat.ainscience.tools;
import org.apache.log4j.Logger;
import org.jdom.Element;

import java.util.*;

/**
 * @author ainlolcat
 * Date: 12/6/11
 */
public class StatisticAggregatorEntity extends AbstractEntity implements UpdateListener {
    private static Logger log = Logger.getLogger(StatisticAggregatorEntity.class);

    EntityCalculator calculator = new EntityCalculator();
    EntityCustomColumnGenerator customColumnGenerator = new EntityCustomColumnGenerator();

    private String template2;
    private String type2;
    private Collection<String> dependencies = new ArrayList<String>();
    private Map<String, String> columnToStat = new HashMap<String, String>();
    private Collection<Entity> handled = new ArrayList<Entity>();

    public StatisticAggregatorEntity(Template template, String type, String template2, String type2){
        this.template = template;
        this.type = type;
        this.template2 = template2;
        this.type2 = type2;
        ID = tools.generateID();
        initColumns();
    }

    public EntityParser getParser() {
        return new StatisticAggregatorEntityParser();
    }

    public String getTemplate2() {
        return template2;
    }

    public void setTemplate2(String template2) {
        this.template2 = template2;
    }

    public String getType2() {
        return type2;
    }

    public void setType2(String type2) {
        this.type2 = type2;
    }

    public void onLoad(){
        dependencies = new ArrayList<String>();

        for (Entity ent:Controller.getInstance().getProject().getEntitiesByType(getType2())){
            if (!handled.contains(ent))
                handleEntity(ent);
        }

        updateState();
    }

    private void initColumns(){
        //name of entities / type(string) / axis / name list
        ColumnImpl col = new ColumnImpl("Entity", MatrixFileParser.MATRIX_DELIMETER_TYPE_STRING, "x0");
        setColumn(col, 0);
        //getData entity description
        Element entityDesc = template.getEntityParseParams(getType());
        //fill entity
        List<Element> columns = entityDesc.getChild("columns").getChildren("column");
        for (Element c:columns){
            String stat = c.getAttributeValue("statistic");
            String cName = c.getAttributeValue("name");
            columnToStat.put(cName, stat);
            col = new ColumnImpl(cName,
                    tools.parseInteger(c.getAttributeValue("type")),
                    c.getAttributeValue("axis")
            );
            new ThresholdHelper().searchThresholdAndApply(col, c);
            setColumn(col, tools.parseInteger(c.getAttributeValue("id")));
        }
    }

    private synchronized void handleEntity(Entity entity){
        Map<String, String> stat = Collections.emptyMap();
        try{
            entity.registerListener(this);
            stat = new StatisticsCollectorImpl(entity).collect();
        }catch(Throwable e){
            log.error("Cannot load statistics for entity: " + entity.getName(), e);
        }
        getColumnByName("Entity").addValue(entity.getName());
        for (Column column : data.values()){
            String statName = columnToStat.get(column.getName());
            if (statName == null) continue;
            String value = stat.get(statName);
            column.addValue(value);
        }
        handled.add(entity);
    }

    private void updateState(){
        try{
            calculator.calculate(this);
        } catch(Exception ex){
            log.error("Cannot calculate columns", ex);
        }
        try{
            customColumnGenerator.generateCustomColumns(this);
        } catch(Exception ex){
            log.error("Cannot generate custom columns", ex);
        }
        Controller.getInstance().throwUpdateEvent(this, UPDATE_ENTITY_COLUMN);
    }

    public void onProjectUpdate() {
        log.debug("Update event income for project to entry " + getName());
        //handled = new ArrayList<Entity>();
        onLoad();
    }

    public void onEntityUpdate(Entity entity, int ation) {
        log.debug("Update event income for entity " + entity.getName() + " to entry " + getName());
        if (dependencies.contains(entity.getName())){
            log.debug("Entity " + entity.getName() + " was found in dependencies list of  " + getName() + " start processing");
            handled = new ArrayList<Entity>();
            onLoad();
        }
        if (entity.getType().equals(getType2()) && !handled.contains(entity)){
            log.debug("Entity " + entity.getName() + " was not handled yet in  " + getName() + " start processing entry");
            handleEntity(entity);
            updateState();
        }
    }
}
